// $Id: pstring_ref.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_PROXY_PSTRING_REF_HPP
#define XPCOM_PROXY_PSTRING_REF_HPP

#include <xpcom/config.hpp>
#include <xpcom/types.hpp>
#include <xpcom/assert.hpp>
#include <xpcom/char_traits.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {
namespace proxy {

//
// Proxy type of character string for convenient use.
// Allows assign from character string pointers and XPCOM strings.
//
// Note for equality comparison: null string pointer and empty character string
//  are NOT considered equal, while null string pointer and empty basic_string
//  ARE equal.
//
template <typename CharT>
class pstring_ref
{
    typedef pstring_ref<CharT> this_type;
public:
    typedef CharT value_type;
    typedef uint32_t size_type;

    pstring_ref() :
        pstr_(0)
    {
    }

    pstring_ref(const pstring_ref& rhs)
    {
        init(rhs.pstr_);
    }

    pstring_ref(const value_type* s, size_type n = static_cast<size_type>(-1))
    {
        init(s, n);
    }

    pstring_ref(const basic_string<value_type>& s)
    {
        init(s);
    }

    XPCOM_DECL ~pstring_ref();

    const value_type* get() const
    {
        return pstr_;
    }

    value_type* get()
    {
        return pstr_;
    }

    operator const value_type*() const
    {
        return pstr_;
    }

    operator value_type*()
    {
        return pstr_;
    }

    value_type operator[](size_type pos) const
    {
        // Can be at terminator
        XPCOM_ASSERT(pstr_ && pos <= char_traits<value_type>::length(pstr_));
        return pstr_[pos];
    }

    value_type& operator[](size_type pos)
    {
        XPCOM_ASSERT(pstr_ && pos < char_traits<value_type>::length(pstr_));
        return pstr_[pos];
    }

    pstring_ref& operator=(const pstring_ref& rhs)
    {
        return assign(rhs);
    }

    pstring_ref& operator=(const value_type* s)
    {
        return assign(s);
    }

    pstring_ref& operator=(const basic_string<value_type>& s)
    {
        return assign(s);
    }

    pstring_ref& assign(const pstring_ref& rhs)
    {
        this_type(rhs).swap(*this);
        return *this;
    }

    pstring_ref& assign(
            const value_type* s, size_type n = static_cast<size_type>(-1))
    {
        this_type(s, n).swap(*this);
        return *this;
    }

    pstring_ref& assign(const basic_string<value_type>& s)
    {
        this_type(s).swap(*this);
        return *this;
    }

    bool equal(const pstring_ref& rhs) const
    {
        return equal(rhs.pstr_);
    }

    XPCOM_DECL bool equal(
            const value_type* s,
            size_type n = static_cast<size_type>(-1)) const;

    XPCOM_DECL bool equal(const basic_string<value_type>& s) const;

    void swap(pstring_ref& rhs)
    {
        value_type* tmp = pstr_;
        pstr_ = rhs.pstr_;
        rhs.pstr_ = tmp;
    }

private:
    XPCOM_DECL void init(
            const value_type* s, size_type n = static_cast<size_type>(-1));
    XPCOM_DECL void init(const basic_string<value_type>& s);

    value_type* pstr_;
};

template <typename CharT>
inline bool
operator==(const pstring_ref<CharT>& lhs, const pstring_ref<CharT>& rhs)
{
    return lhs.equal(rhs);
}

template <typename CharT>
inline bool
operator==(const pstring_ref<CharT>& lhs, const CharT* rhs)
{
    return lhs.equal(rhs);
}

template <typename CharT>
inline bool
operator==(const CharT* lhs, const pstring_ref<CharT>& rhs)
{
    return rhs.equal(lhs);
}

template <typename CharT>
inline bool
operator==(const pstring_ref<CharT>& lhs, const basic_string<CharT>& rhs)
{
    return lhs.equal(rhs);
}

template <typename CharT>
inline bool
operator==(const basic_string<CharT>& lhs, const pstring_ref<CharT>& rhs)
{
    return rhs.equal(lhs);
}

template <typename CharT>
inline bool
operator!=(const pstring_ref<CharT>& lhs, const pstring_ref<CharT>& rhs)
{
    return !(lhs == rhs);
}

template <typename CharT>
inline bool
operator!=(const pstring_ref<CharT>& lhs, const CharT* rhs)
{
    return !(lhs == rhs);
}

template <typename CharT>
inline bool
operator!=(const CharT* lhs, const pstring_ref<CharT>& rhs)
{
    return !(lhs == rhs);
}

template <typename CharT>
inline bool
operator!=(const pstring_ref<CharT>& lhs, const basic_string<CharT>& rhs)
{
    return !(lhs == rhs);
}

template <typename CharT>
inline bool
operator!=(const basic_string<CharT>& lhs, const pstring_ref<CharT>& rhs)
{
    return !(lhs == rhs);
}

// swap
template <typename CharT>
inline void swap(pstring_ref<CharT>& lhs, pstring_ref<CharT>& rhs)
{
    lhs.swap(rhs);
}

} // namespace xpcom::proxy
} // namespace xpcom

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_PROXY_PSTRING_REF_HPP
